package com.wt.admin.config.aspect;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.aizuda.easy.security.domain.Rep;
import com.aizuda.easy.security.util.LocalUtil;
import com.wt.admin.config.aspect.annotation.LogAno;
import com.wt.admin.domain.entity.sys.SysOperationLogEntity;
import com.wt.admin.domain.vo.sys.UserVO;
import com.wt.admin.service.sys.SysOperationLogService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;


@Aspect
@Component
@Slf4j
public class LogAspect {

    @Resource
    private SysOperationLogService sysOperationLogService;
    private final List<SysOperationLogEntity> logQueue = new ArrayList<>();
    private final SysOperationLogEntity logEntity = new SysOperationLogEntity();

    public void init(){
        consume();
    }

    /**
     * 操作日志 人，时间，ip，方法名，参数，返回值，执行时间
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("execution(* com.wt.admin.controller..*(..))")
    public Object Around(ProceedingJoinPoint point) throws Throwable {
        // 获取request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String requestUrl = request.getRequestURL().toString();
        long startTime = System.currentTimeMillis();
        Object result = null;
        // 执行方法
        MethodSignature method = (MethodSignature) point.getSignature();
        LogAno logAno = method.getMethod().getDeclaredAnnotation(LogAno.class);
        try {
            result = point.proceed();
        }finally {
            if(ObjectUtil.isNotEmpty(logAno)){
                produce(startTime,logAno.name(),method.getMethod().getName(),requestUrl,point.getArgs(),result);
            }
        }
        return result;
    }

    private void produce(long startTime,String name,String method,String url,Object[] args,Object result) {
        Object obj = analysisArgs(args);
        SysOperationLogEntity clone = logEntity.clone();
        UserVO user = LocalUtil.getUserOrNull();
        clone.setUserId(ObjectUtil.isEmpty(user)? null: user.getId());
        clone.setLogName(name);
        clone.setLogMethod(method);
        clone.setLogPath(url);
        clone.setLogParam(obj);
        clone.setLogResultCode(JSONUtil.toBean(JSONUtil.toJsonStr(result), Rep.class).getCode());
        clone.setCreateTime(DateUtil.now());
        long endTime = System.currentTimeMillis();
        clone.setLogTime((int) (endTime - startTime));
        logQueue.add(clone);
    }


    private void consume(){
        Thread thread = new Thread(() -> {
            while (true){
                try {
                    if(logQueue.isEmpty()){
                        ThreadUtil.sleep(5000);
                        continue;
                    }
                    sysOperationLogService.add(logQueue);
                    logQueue.clear();
                }catch (Exception e){
                    log.error("操作日志错误 :{}",e.getMessage());
                    ThreadUtil.sleep(3000);
                }
            }
        });
        thread.setName("操作日志消费");
        thread.start();
    }

    /**
     * 解析参数
     * @param args
     */
    private Object analysisArgs(Object[] args){
        if(args == null || args.length < 1){
            return null;
        }
        return args[0];
    }

}
